/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef WDG_REG_ACCESS_H
#define WDG_REG_ACCESS_H

/*!
 * @file wdg_reg_access.h
 * @brief This file declares or defines pmc register access functions
 */

/*******Includes***************************************************************/
#include "device_registers.h"
#include "errcodes.h"
#include "wdg_drv.h"

/*******Definitions************************************************************/
#define WDG_UNLOCK(regBase) \
do {\
    (regBase)->CNT = CONFIG_WDG_UNLOCK_VALUE; \
} while(0)

#define WDG_CS_RESET_VALUE   (0x120U)
#define WDG_TO_RESET_VALUE   (0x1000U)
#define WDG_WIN_RESET_VALUE  (0x0U)

#define WDG_CS_WIN(x)     (((uint32_t)(((uint32_t)(x)) << WDG_CS_WIN_Pos)) & WDG_CS_WIN_Msk)
#define WDG_CS_INT(x)     (((uint32_t)(((uint32_t)(x)) << WDG_CS_INT_Pos)) & WDG_CS_INT_Msk)
#define WDG_CS_FLG(x)     (((uint32_t)(((uint32_t)(x)) << WDG_CS_FLG_Pos)) & WDG_CS_FLG_Msk)
#define WDG_CS_CLK(x)     (((uint32_t)(((uint32_t)(x)) << WDG_CS_CLK_Pos)) & WDG_CS_CLK_Msk)
#define WDG_CS_PRES(x)    (((uint32_t)(((uint32_t)(x)) << WDG_CS_PRES_Pos)) & WDG_CS_PRES_Msk)
#define WDG_CS_UPDATE(x)  (((uint32_t)(((uint32_t)(x)) << WDG_CS_UPDATE_Pos)) & WDG_CS_UPDATE_Msk)

/*! @brief WDG mininum timeout value */
#define WDG_MIN_TIMEOUT_VALUE        (0U)
/*! @brief WDG default timeout value */
#define WDG_TIMEOUT_DEFAULT_VALUE    (0x1000)

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief WDG init
 *
 * @param[in] regBase: The WDG register base address
 * @param[in] wdgConfig: The WDG config
 * @return ERR_SUCCESS:Success
 *         ERR_ERROR:Failed
 */
errcode_t WDG_REG_Init(WDG_Type* regBase, const wdg_config_t* wdgConfig);

/*!
 * @brief WDG deinit
 *
 * @param[in] regBase: The WDG register base address
 * @return ERR_SUCCESS:Success
 *         ERR_ERROR:Failed
 */
void WDG_REG_Deinit(WDG_Type* regBase);

/*!
 * @brief Get WDG current config
 *
 * @param[in] regBase: The WDG register base address
 * @return The current config
 */
wdg_config_t WDG_REG_GetConfig(const WDG_Type* regBase);


/*!
 * @brief Set interrupt enable/disable
 *
 * @param[in] regBase: The WDG register base address
 * @param[in] enable: ture - Enable
                      false - Disable
 * @return None
 */
void WDG_REG_SetIntEnable(WDG_Type* regBase, bool enable);

/*!
 * @brief Check if the last configuration was complete
 *
 * @param[in] regBase: The WDG register base address
 * @return ture: The configuration was complete
           false: The configuration was not complete
 */
static inline bool WDG_REG_IsReconfigurationComplete(const WDG_Type* regBase)
{
    return ((regBase->CS & WDG_CS_RCS_Msk) >> WDG_CS_RCS_Pos) != 0U;
}

/*!
 * @brief Check if WDG is update enabled
 *
 * @param[in] regBase: The WDG register base address
 * @return ture: Updates are allowed
 *         false: Updates are not allowed
 */
static inline bool WDG_REG_IsUpdateEnable(const WDG_Type* regBase)
{
    return ((regBase->CS & WDG_CS_UPDATE_Msk) >> WDG_CS_UPDATE_Pos) != 0U;
}

/*!
 * @brief Check if WDG is unlocked
 *
 * @param[in] regBase: The WDG register base address
 * @return ture: Unlocked
 *         false: Locked
 */
static inline bool WDG_IsUnlocked(const WDG_Type* regBase)
{
    return ((regBase->CS & WDG_CS_LOCK_Msk) >> WDG_CS_LOCK_Pos) != 0U;
}

/*!
 * @brief Check if WDG is enabled
 *
 * @param[in] regBase: The WDG register base address
 * @return ture: Enabled
 *         false: Disabled
 */
static inline bool WDG_REG_IsEnabled(const WDG_Type* regBase)
{
    return ((regBase->CS & WDG_CS_EN_Msk) >> WDG_CS_EN_Pos) != 0U;
}

/*!
 * @brief Set window mode
 *
 * @param[in] regBase: The WDG register base address
 * @param[in] enable: ture - Enable
                      false - Disable
 * @return None
 */
static inline void WDG_REG_SetWindowMode(WDG_Type* regBase, bool enable)
{
    WDG_UNLOCK(regBase);
    regBase->CS = (regBase->CS & ~WDG_CS_WIN_Msk) | WDG_CS_WIN(enable ? 1UL : 0UL);
}

/*!
 * @brief Set window value
 *
 * @param[in] regBase: The WDG register base address
 * @param[in] windowValue: Window value
 * @return None
 */
static inline void WDG_REG_SetWindowValue(WDG_Type* regBase, uint16_t windowValue)
{
    WDG_UNLOCK(regBase);
    regBase->WIN = windowValue;
}

/*!
 * @brief Set timeout value
 *
 * @param[in] regBase: The WDG register base address
 * @param[in] timeoutValue: Total timeout value
 * @return None
 */
static inline void WDG_REG_SetTimeout(WDG_Type* regBase, uint16_t timeoutValue)
{
    WDG_UNLOCK(regBase);
    regBase->TOVAL = timeoutValue;
}

/*!
 * @brief Refresh WDG counter
 *
 * @param[in] regBase: The WDG register base address
 * @return None
 */
static inline void WDG_REG_Refresh(WDG_Type* regBase)
{
    regBase->CNT = CONFIG_WDG_REFRESH_VALUE;
}

/*!
 * @brief Clear interrupt flag
 *
 * @param[in] regBase: The WDG register base address
 * @return None
 */
static inline void WDG_REG_ClearInterruptFlag(WDG_Type* regBase)
{
    WDG_UNLOCK(regBase);
    regBase->CS = (regBase->CS & ~WDG_CS_FLG_Msk) | WDG_CS_FLG(1U);
}

/*!
 * @brief Get current wdg counter
 *
 * @param[in] regBase: The WDG register base address
 * @return the counter value
 */
static inline uint16_t WDG_REG_GetCounter(const WDG_Type* regBase)
{
    return (uint16_t)regBase->CNT;
}

#if defined(__cplusplus)
}
#endif

#endif /* WDG_REG_ACCESS_H */

/*******EOF********************************************************************/
